using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;

namespace CKY.AgentPlatform.Caching
{
    /// <summary>
    /// Redis缓存服务
    /// </summary>
    public class RedisCacheService : ITransientDependency
    {
        private readonly IConnectionMultiplexer _redis;
        private readonly IDistributedCache _distributedCache;
        private readonly ILogger<RedisCacheService> _logger;
        private readonly ICurrentTenant _currentTenant;
        private readonly RedisCacheOptions _options;
        private readonly DistributedCacheService _cacheService;

        public RedisCacheService(
            IConnectionMultiplexer redis,
            IDistributedCache distributedCache,
            ILogger<RedisCacheService> logger,
            ICurrentTenant currentTenant,
            IOptions<RedisCacheOptions> options,
            DistributedCacheService cacheService)
        {
            _redis = redis;
            _distributedCache = distributedCache;
            _logger = logger;
            _currentTenant = currentTenant;
            _options = options.Value;
            _cacheService = cacheService;
        }

        /// <summary>
        /// 获取Redis数据库
        /// </summary>
        private IDatabase GetDatabase()
        {
            return _redis.GetDatabase();
        }

        /// <summary>
        /// 获取Redis服务器
        /// </summary>
        private IServer GetServer()
        {
            var endpoints = _redis.GetEndPoints();
            return _redis.GetServer(endpoints.First());
        }

        /// <summary>
        /// 获取缓存统计信息
        /// </summary>
        public async Task<RedisStatistics> GetStatisticsAsync()
        {
            try
            {
                var server = GetServer();
                var info = await server.InfoAsync("memory");
                var memoryInfo = info.FirstOrDefault();

                var db = GetDatabase();
                var keysCount = await _cacheService.GetLongAsync("statistics:keys:count");
                var cacheHitRate = await _cacheService.GetDoubleAsync("statistics:hit:rate");
                var avgResponseTime = await _cacheService.GetDoubleAsync("statistics:response:time");

                return new RedisStatistics
                {
                    UsedMemory = ParseMemory(memoryInfo?.FirstOrDefault(x => x.Key.StartsWith("used_memory:"))?.Value),
                    MaxMemory = ParseMemory(memoryInfo?.FirstOrDefault(x => x.Key == "used_memory_peak")?.Value),
                    KeyspaceHits = await db.StringGetAsync("statistics:hits"),
                    KeyspaceMisses = await db.StringGetAsync("statistics:misses"),
                    ConnectedClients = await db.StringGetAsync("statistics:clients"),
                    TotalCommandsProcessed = await db.StringGetAsync("statistics:commands"),
                    KeysCount = keysCount,
                    CacheHitRate = cacheHitRate,
                    AverageResponseTime = avgResponseTime
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取Redis统计信息失败");
                return new RedisStatistics();
            }
        }

        /// <summary>
        /// 更新统计信息
        /// </summary>
        public async Task UpdateStatisticsAsync(bool isHit, double responseTime)
        {
            try
            {
                var db = GetDatabase();
                
                // 更新命中/未命中计数
                if (isHit)
                {
                    await db.StringIncrementAsync("statistics:hits");
                }
                else
                {
                    await db.StringIncrementAsync("statistics:misses");
                }

                // 更新响应时间
                await db.StringIncrementAsync("statistics:response:time", responseTime);
                
                // 更新命令计数
                await db.StringIncrementAsync("statistics:commands");

                // 计算命中率
                var hits = await db.StringGetAsync("statistics:hits");
                var misses = await db.StringGetAsync("statistics:misses");
                if (hits.HasValue && misses.HasValue)
                {
                    var hitRate = (double)hits / (double)(hits + misses);
                    await _cacheService.SetDoubleAsync("statistics:hit:rate", hitRate, CacheExpiration.Short);
                }

                // 计算平均响应时间
                var totalResponseTime = await db.StringGetAsync("statistics:response:time");
                var totalCommands = await db.StringGetAsync("statistics:commands");
                if (totalResponseTime.HasValue && totalCommands.HasValue && totalCommands > 0)
                {
                    var avgResponseTime = (double)totalResponseTime / (double)totalCommands;
                    await _cacheService.SetDoubleAsync("statistics:response:time", avgResponseTime, CacheExpiration.Short);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新Redis统计信息失败");
            }
        }

        /// <summary>
        /// 获取慢查询日志
        /// </summary>
        public async Task<List<SlowQueryLog>> GetSlowQueryLogsAsync(int count = 100)
        {
            try
            {
                var db = GetDatabase();
                var logs = new List<SlowQueryLog>();

                for (int i = 0; i < count; i++)
                {
                    var key = $"slowquery:{i}";
                    var log = await db.StringGetAsync(key);
                    if (log.HasValue)
                    {
                        logs.Add(System.Text.Json.JsonSerializer.Deserialize<SlowQueryLog>(log));
                    }
                }

                return logs.OrderByDescending(x => x.ExecutionTime).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取慢查询日志失败");
                return new List<SlowQueryLog>();
            }
        }

        /// <summary>
        /// 记录慢查询
        /// </summary>
        public async Task LogSlowQueryAsync(string operation, string query, long executionTime)
        {
            try
            {
                var db = GetDatabase();
                var log = new SlowQueryLog
                {
                    Timestamp = DateTime.UtcNow,
                    Operation = operation,
                    Query = query,
                    ExecutionTime = executionTime,
                    UserAgent = "System"
                };

                var serialized = System.Text.Json.JsonSerializer.Serialize(log);
                var key = $"slowquery:{DateTime.UtcNow.Ticks}";
                
                await db.StringSetAsync(key, serialized, TimeSpan.FromDays(7));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录慢查询失败");
            }
        }

        /// <summary>
        /// 清除指定模式的缓存
        /// </summary>
        public async Task ClearPatternAsync(string pattern)
        {
            try
            {
                var server = GetServer();
                var db = GetDatabase();
                var keys = server.Keys(pattern: pattern).ToArray();

                if (keys.Any())
                {
                    await db.KeyDeleteAsync(keys);
                    _logger.LogInformation("清除模式缓存: {Pattern}, 清除数量: {Count}", pattern, keys.Length);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清除模式缓存失败: {Pattern}", pattern);
            }
        }

        /// <summary>
        /// 获取缓存键列表
        /// </summary>
        public async Task<List<string>> GetKeysAsync(string pattern = "*")
        {
            try
            {
                var server = GetServer();
                var keys = server.Keys(pattern: pattern);
                return keys.Select(k => k.ToString()).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取缓存键列表失败: {Pattern}", pattern);
                return new List<string>();
            }
        }

        /// <summary>
        /// 批量设置缓存
        /// </summary>
        public async Task SetManyAsync(Dictionary<string, string> items, TimeSpan? expiration = null)
        {
            try
            {
                var db = GetDatabase();
                var tasks = new List<Task>();

                foreach (var item in items)
                {
                    var task = db.StringSetAsync(
                        GetCacheKey(item.Key),
                        item.Value,
                        expiration ?? TimeSpan.FromMinutes(30));
                    tasks.Add(task);
                }

                await Task.WhenAll(tasks);
                _logger.LogDebug("批量设置缓存成功，数量: {Count}", items.Count);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量设置缓存失败");
            }
        }

        /// <summary>
        /// 批量获取缓存
        /// </summary>
        public async Task<Dictionary<string, string>> GetManyAsync(List<string> keys)
        {
            try
            {
                var db = GetDatabase();
                var redisKeys = keys.Select(k => new RedisKey(GetCacheKey(k))).ToArray();
                var values = await db.StringGetAsync(redisKeys);

                var result = new Dictionary<string, string>();
                for (int i = 0; i < keys.Count; i++)
                {
                    if (values[i].HasValue)
                    {
                        result[keys[i]] = values[i];
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量获取缓存失败");
                return new Dictionary<string, string>();
            }
        }

        /// <summary>
        /// 检查Redis健康状态
        /// </summary>
        public async Task<bool> CheckHealthAsync()
        {
            try
            {
                var db = GetDatabase();
                return await db.PingAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis健康检查失败");
                return false;
            }
        }

        /// <summary>
        /// 获取Redis信息
        /// </summary>
        public async Task<Dictionary<string, string>> GetRedisInfoAsync()
        {
            try
            {
                var server = GetServer();
                var info = await server.InfoAsync();
                var result = new Dictionary<string, string>();

                foreach (var group in info)
                {
                    foreach (var entry in group)
                    {
                        result[$"{group.Group}:{entry.Key}"] = entry.Value;
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取Redis信息失败");
                return new Dictionary<string, string>();
            }
        }

        private string GetCacheKey(string key)
        {
            var prefix = GetCachePrefix();
            return $"{prefix}:{key}";
        }

        private string GetCachePrefix()
        {
            var tenantId = _currentTenant.Id?.ToString("N") ?? "default";
            return $"AgentPlatform:{tenantId}";
        }

        private long ParseMemory(string memoryValue)
        {
            if (string.IsNullOrEmpty(memoryValue))
                return 0;

            var value = memoryValue.TrimEnd('b', 'B');
            if (value.EndsWith("k", StringComparison.OrdinalIgnoreCase))
                return long.Parse(value.TrimEnd('k', 'K')) * 1024;
            if (value.EndsWith("m", StringComparison.OrdinalIgnoreCase))
                return long.Parse(value.TrimEnd('m', 'M')) * 1024 * 1024;
            if (value.EndsWith("g", StringComparison.OrdinalIgnoreCase))
                return long.Parse(value.TrimEnd('g', 'G')) * 1024 * 1024 * 1024;

            return long.Parse(value);
        }
    }

    /// <summary>
    /// Redis统计信息
    /// </summary>
    public class RedisStatistics
    {
        public long UsedMemory { get; set; }
        public long MaxMemory { get; set; }
        public long KeyspaceHits { get; set; }
        public long KeyspaceMisses { get; set; }
        public long ConnectedClients { get; set; }
        public long TotalCommandsProcessed { get; set; }
        public long KeysCount { get; set; }
        public double CacheHitRate { get; set; }
        public double AverageResponseTime { get; set; }

        public double HitRatePercentage
        {
            get
            {
                var total = KeyspaceHits + KeyspaceMisses;
                return total > 0 ? (double)KeyspaceHits / total * 100 : 0;
            }
        }

        public string UsedMemoryFormatted => FormatBytes(UsedMemory);
        public string MaxMemoryFormatted => FormatBytes(MaxMemory);

        private string FormatBytes(long bytes)
        {
            string[] sizes = { "B", "KB", "MB", "GB", "TB" };
            double len = bytes;
            int order = 0;
            
            while (len >= 1024 && order < sizes.Length - 1)
            {
                order++;
                len = len / 1024;
            }

            return $"{len:0.##} {sizes[order]}";
        }
    }

    /// <summary>
    /// 慢查询日志
    /// </summary>
    public class SlowQueryLog
    {
        public DateTime Timestamp { get; set; }
        public string Operation { get; set; }
        public string Query { get; set; }
        public long ExecutionTime { get; set; }
        public string UserAgent { get; set; }
    }

    /// <summary>
    /// Redis缓存选项
    /// </summary>
    public class RedisCacheOptions
    {
        public string ConnectionString { get; set; } = "localhost:6379";
        public string InstanceName { get; set; } = "AgentPlatform";
        public int Database { get; set; } = 0;
        public int ConnectTimeout { get; set; } = 5000;
        public int SyncTimeout { get; set; } = 5000;
        public bool AllowAdmin { get; set; } = false;
        public string Password { get; set; }
        public bool AbortOnConnectFail { get; set; } = true;
        public bool Ssl { get; set; } = false;
    }

    /// <summary>
    /// 缓存服务扩展方法
    /// </summary>
    public static class CacheServiceExtensions
    {
        public static async Task<T> GetAsync<T>(this DistributedCacheService cacheService, string key, Func<Task<T>> factory, TimeSpan? expiration = null)
        {
            return await cacheService.GetAsync(key, factory, expiration);
        }

        public static async Task SetAsync<T>(this DistributedCacheService cacheService, string key, T value, TimeSpan? expiration = null)
        {
            await cacheService.SetAsync(key, value, expiration);
        }

        public static async Task<bool> GetBooleanAsync(this DistributedCacheService cacheService, string key)
        {
            return await cacheService.GetAsync<bool>(key);
        }

        public static async Task SetBooleanAsync(this DistributedCacheService cacheService, string key, bool value, TimeSpan? expiration = null)
        {
            await cacheService.SetAsync(key, value, expiration);
        }

        public static async Task<long> GetLongAsync(this DistributedCacheService cacheService, string key)
        {
            return await cacheService.GetAsync<long>(key);
        }

        public static async Task SetLongAsync(this DistributedCacheService cacheService, string key, long value, TimeSpan? expiration = null)
        {
            await cacheService.SetAsync(key, value, expiration);
        }

        public static async Task<double> GetDoubleAsync(this DistributedCacheService cacheService, string key)
        {
            return await cacheService.GetAsync<double>(key);
        }

        public static async Task SetDoubleAsync(this DistributedCacheService cacheService, string key, double value, TimeSpan? expiration = null)
        {
            await cacheService.SetAsync(key, value, expiration);
        }
    }
}